//#####################################################################
/*
 * TITULO: Clase Expresion regular
 * AUTORES: Mora Rodriguez Carolina
 * MATERIA: Compiladores
 * GRUPO: 3CM6
 * PROFESOR: Juarez Gambino Joel Omar
 */
//#####################################################################

//********************************************************************
//BIBLIOTECAS
//********************************************************************
import java.io.*;
import java.util.ArrayList;

//#####################################################################
//CLASE
//#####################################################################
/*
* DESCRIPCION: 
*/
public class Reconocedor {
	//********************************************************************
	//PARAMETROS
	//********************************************************************
	private static ArrayList<String> EstructuraSelectiva = new ArrayList<String>();
	private static ArrayList<String> EstructuraRepetitiva = new ArrayList<String>();
	private static ArrayList<String> TipoDato = new ArrayList<String>();
	static int indice;
	static int cont_linea;
	static ArrayList TablaSimbolos=new ArrayList();
	static ArrayList Errores=new ArrayList();
	
	//-------------------------- GETS -----------------------------------
	
	//-------------------------- SETS -----------------------------------
	
	//********************************************************************
	//CONSTRUCTOR
	//********************************************************************
	public Reconocedor ()
	{
		EstructuraSelectiva.add("if"); 
		EstructuraSelectiva.add("switch-case");
		EstructuraRepetitiva.add("for");
		EstructuraRepetitiva.add("while");
		EstructuraRepetitiva.add("do-while");
		TipoDato.add("int");
		TipoDato.add("float");
		TipoDato.add("char");
		TipoDato.add("double");
	}
	
	//********************************************************************
	//PRUEBA DE FUNCIONAMIENTO
	//********************************************************************
	/*public static void main (String args[])
	{
		Reconocedor reconocedor = new Reconocedor();
		char[] array = ";".toCharArray();
		indice = 0;
		cont_linea=0;
		
			//---------------------------------------------------------------------------
			//if(reconocedor.Identificador(array))
				//System.out.println("se encontro identificador");
			//if(reconocedor.Flotante(array))
				//System.out.println("se encontro numero flotante");
			//if(reconocedor.Entero(array))
				//System.out.println("se encontro numero entero");
			//if(reconocedor.IdentificadorMF(array))
				//System.out.println("se encontro identificador mal formado");
			//if(reconocedor.Caracter(array))
				//System.out.println("se encontro caracter o caracter mal formado");
			//if(reconocedor.Cadenas(array))
				//System.out.println("se encontro cadena o cadena mal formado");
			//if(reconocedor.OperadoresAritmeticosIncremento(array))
				//System.out.println("se encontro un operador aritmetico o incremento");
			//if(reconocedor.OperadoresRacionalesAsignacion(array))
				//System.out.println("se encontro un operador racional o una asignacion");
			//if(reconocedor.OperadoresLogicos(array))
				//System.out.println("se encontro un operador logico");
			if(reconocedor.SimbolosEspeciales(array))
				System.out.println("se encontro un simbolo especial");
			//if(reconocedor.Ignorar(array))
				//System.out.println("se ignoro algo");
			//---------------------------------------------------------------------------
			
		System.out.println("indice: "+indice+"\tErrores: "+Errores.toString()+"\tTablaSimbolos: "+TablaSimbolos.toString());
	}
	
	//********************************************************************
	//METODOS
	//********************************************************************/
	
	/*---------------- FUNCION RECONOCER IDENTIFICADOR --------------------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean Identificador (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		Componente componente;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(Character.isLetter(caracter) | caracter=='_')
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(1):
					if(Character.isLetter(caracter) | Character.isDigit(caracter) | caracter=='_')
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
						estado = 2;
					break;
				case(2):
					componente = PalabraReservada (posible);
					TablaSimbolos.add(componente);
					return true;
			}
		}
	}
	
	/*---------------- FUNCION RECONOCER SI ES PALABRA RESERVADA ------------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public static Componente PalabraReservada (String identificador)
	{
		Componente componente = new Componente(null, null, null);
		if(EstructuraSelectiva.contains(identificador))
			componente.setComp_lexico("ESTRUCTURA SELECTIVA");
		else if(EstructuraRepetitiva.contains(identificador))
			componente.setComp_lexico("ESTRUCTURA REPETITIVA");
		else
			componente.setComp_lexico("IDENTIFICADOR");
		
		componente.setLexema(identificador);
		componente.setValor(identificador);
		
		return componente;
	}
	
	/*---------------- FUNCION RECONOCER IDENTIFICADOR MAL FORMADO ---------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean IdentificadorMF (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(Character.isDigit(caracter))
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(1):
					if(Character.isDigit(caracter) | Character.isLetter(caracter) | caracter=='_')
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						cont_char++;
						estado = 2;
					}
					break;
				case(2):
					Errores.add(cont_linea+"\t\t"+posible);
					return true;
			}
		}
	}
	
	/*---------------- FUNCION RECONOCER NUMERO FLOTANTE ------------------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean Flotante (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		Componente componente;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(Character.isDigit(caracter))
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(1):
					if(Character.isDigit(caracter))
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(caracter=='.')
					{
						estado = 2;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(2):
					if(Character.isDigit(caracter))
					{
						estado = 2;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(!(Character.isDigit(caracter)))
						estado = 3;
					break;
				case(3):
					componente = new Componente("NUMERO FLOTANTE", posible, posible);
					TablaSimbolos.add(componente);
					return true;
			}
		}
	}
	
	/*---------------- FUNCION RECONOCER NUMERO ENTERO -------------------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean Entero (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		Componente componente;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(Character.isDigit(caracter))
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(1):
					if(Character.isDigit(caracter))
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(!(Character.isDigit(caracter)))
						estado = 2;
					break;
				case(2):
					componente = new Componente("NUMERO ENTERO", posible, posible);
					TablaSimbolos.add(componente);
					return true;
			}
		}
	}
	
	/*---------------- FUNCION RECONOCER CARACTER Y CARACTER MF--------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean Caracter (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		Componente componente;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(caracter=='\'')
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						indice = indice - cont_char++;
						return false;
					}
					break;
				case(1):
					if(!(caracter=='\'' | caracter=='\\'))
					{
						estado = 2;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(caracter=='\'' | caracter=='\\')
						estado = 3;
					break;
				case(2):
					if(caracter == '\'')
					{
						estado = 4;
						posible = posible + caracter;
						cont_char++;
					}
					else if(caracter!='\'')
					{
						estado = 3;
						posible = posible + caracter;
						cont_char++;
					}
					break;
				case(3):
					Errores.add(cont_linea+"\t\t"+posible);
					indice++;
					return true;
				case(4):
					componente = new Componente("CARACTER", posible, posible);
					TablaSimbolos.add(componente);
					indice++;
					return true;
			}
		}
	}
	
	/*---------------- FUNCION RECONOCER CADENA Y CADENA MF---------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean Cadenas (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		Componente componente;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(caracter=='\"')
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						indice = indice - cont_char; 
						return false;
					}
					break;
				case(1):
					if(!(caracter=='\"' | caracter=='\\'))
					{
						estado = 2;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(caracter=='\"' | caracter=='\\')
						estado = 3;
					break;
				case(2):
					if(indice==array.length-1 && caracter!='\"')
					{
						posible = posible + caracter;
						cont_char++;
						estado = 3;
					}
					else if(!(caracter=='\"' | caracter=='\\'))
					{
						estado = 2;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(caracter=='\"')
					{
						estado = 4;
						posible = posible + caracter;
						cont_char++;
					}
					break;
				case(3):
					Errores.add(cont_linea+"\t\t"+posible);
					indice++;
					return true;
				case(4):
					componente = new Componente("CADENA", posible, posible);
					TablaSimbolos.add(componente);
					indice++;
					return true;
			}
		}
	}
	
	/*---------------- FUNCION RECONOCER OPERADORES ARITMETICOS E INCREMENTOS---------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean OperadoresAritmeticosIncremento (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		Componente componente;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(caracter=='+')
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if (caracter=='-')
					{
						estado = 2;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(caracter=='*' | caracter=='/')
					{
						estado = 3;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(1):
					if(caracter=='+'|caracter=='=')
					{
						estado = 4;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(!(caracter=='+' | caracter=='='))
						estado = 5;
					break;
				case(2):
					if(caracter=='-' | caracter=='=')
					{
						estado = 6;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(!(caracter=='-' | caracter=='='))
						estado = 7;
					break;
				case(3):
					if(caracter=='=')
					{
						estado = 8;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(caracter!='=')
						estado = 9;
					break;
				case(4): 
					if(posible.equals("++"))
						componente = new Componente("INCREMENTO", posible, "INCREMENTO POSITIVO");
					else 
						componente = new Componente("INCREMENTO", posible, "SUMA ASIGNACION");
					TablaSimbolos.add(componente);
					return true;
				case(5):
					componente = new Componente("OPERADOR ARITMETICO", posible, "SUMA");
					TablaSimbolos.add(componente);
					return true;
				case(6):
					if(posible.equals("--"))
						componente = new Componente("INCREMENTO", posible, "INCREMENTO NEGATIVO");
					else 
						componente = new Componente("INCREMENTO", posible, "RESTA ASIGNACION");
					TablaSimbolos.add(componente);
					return true;
				case(7):
					componente = new Componente("OPERADOR ARITMETICO", posible, "RESTA");
					TablaSimbolos.add(componente);
					return true;
				case(8):
					if(posible.equals("*="))
						componente = new Componente("INCREMENTO", posible, "MULTIPLICACION ASIGNACION");
					else 
						componente = new Componente("INCREMENTO", posible, "DIVISION ASIGNACION");
					TablaSimbolos.add(componente);
					return true;
				case(9):
					if(posible.equals("*"))
						componente = new Componente("OPERADOR ARITMETICO", posible, "MULTIPLICACION");
					else
						componente = new Componente("OPERADOR ARITMETICO", posible, "DIVISION");
					TablaSimbolos.add(componente);
					return true;
			}
		}
	}
	
	/*---------------- FUNCION RECONOCER OPERADORES RACIONALES Y ASIGNACION--------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean OperadoresRacionalesAsignacion (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		Componente componente;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(caracter=='<'|caracter=='>'|caracter=='=')
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(1):
					if(caracter=='=')
					{
						estado = 2;
						posible = posible + caracter;
						indice++;
						cont_char++;
					}
					else if(caracter!='=')
						estado = 3;
					break;
				case(2):
					if(posible.equals("<="))
						componente = new Componente("OPERADOR RACIONAL", posible, "MENOR IGUAL");
					else if(posible.equals(">="))
						componente = new Componente("OPERADOR RACIONAL", posible, "MAYOR IGUAL");
					else
						componente = new Componente("OPERADOR RACIONAL", posible, "IGUAL");
					TablaSimbolos.add(componente);
					return true;
				case(3):
					if(posible.equals("="))
						componente = new Componente("ASIGNACION", posible, "ASIGNACION");
					else if(posible.equals(">"))
						componente = new Componente("OPERADOR RACIONAL", posible, "MAYOR");
					else
						componente = new Componente("OPERADOR RACIONAL", posible, "MENOR");
					TablaSimbolos.add(componente);
					return true;
			}
		}
	}
	
	/*---------------- FUNCION RECONOCER OPERADORES LOGICOS---------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean OperadoresLogicos (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		Componente componente;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(caracter=='&')
					{
						estado = 1;
						posible = posible + caracter;
						indice++;
						cont_char++;
					}
					else if(caracter=='|')
					{
						estado = 2;
						posible = posible + caracter;
						indice++;
						cont_char++;
					}
					else if(caracter=='!')
					{
						estado = 3;
						posible = posible + caracter;
						indice++;
						cont_char++;
					}
					else 
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(1):
					if(caracter == '&')
					{
						estado = 4;
						posible = posible + caracter;
						indice++;
						cont_char++;
					}
					else 
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(2):
					if(caracter == '|')
					{
						estado = 5;
						posible = posible + caracter;
						indice++;
						cont_char++;
					}
					else 
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(3):
					if(caracter == '=')
					{
						estado = 6;
						posible = posible + caracter;
						cont_char++;
						indice++;
					}
					else if(caracter!='=')
						estado = 7;
					break;
				case(4):
					componente = new Componente("OPERADOR LOGICO", posible, "Y");
					TablaSimbolos.add(componente);
					return true;
				case(5):
					componente = new Componente("OPERADOR LOGICO", posible, "O");
					TablaSimbolos.add(componente);
					return true;
				case(6):
					componente = new Componente("OPERADOR LOGICO", posible, "DIFERENTE");
					TablaSimbolos.add(componente);
					return true;
				case(7):
					componente = new Componente("OPERADOR LOGICO", posible, "NEGACION");
					TablaSimbolos.add(componente);
					return true;
			}
		}
	}
	
	/*---------------- FUNCION RECONOCER SIMBOLOS ESPECIALES -------------------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean SimbolosEspeciales (char[] array)
	{
		int estado = 0;
		String posible = new String();
		char caracter;
		Componente componente;
		int cont_char=0;
		
		while(true)
		{
			caracter = array[indice];
			switch(estado)
			{
				case(0):
					if(caracter=='('|caracter==')'|caracter=='}'|caracter=='{'|caracter==';'|caracter==','|caracter==':'|
						caracter=='['|caracter==']'|caracter=='.')
					{
						estado = 1;
						posible = posible + caracter;
						cont_char++;
					}
					else
					{
						indice = indice - cont_char;
						return false;
					}
					break;
				case(1):
					if(posible.equals("{"))
						componente = new Componente("SIMBOLO ESPECIAL", posible, "LLAVE QUE ABRE");
					else if(posible.equals("}"))
						componente = new Componente("SIMBOLO ESPECIAL", posible, "LLAVE QUE CIERRA");
					else if(posible.equals("["))
						componente = new Componente("SIMBOLO ESPECIAL", posible, "CORCHETE ABIERTO");
					else if(posible.equals("]"))
						componente = new Componente("SIMBOLO ESPECIAL", posible, "CORCHETE CERRADO");
					else if(posible.equals("("))
						componente = new Componente("SIMBOLO ESPECIAL", posible, "PARENTESIS QUE ABRE");
					else if(posible.equals(")"))
						componente = new Componente("SIMBOLO ESPECIAL", posible, "PARENTESIS QUE CIERRA");
					else if(posible.equals(":"))
						componente = new Componente("SIMBOLO ESPECIAL", posible, "DOS PUNTOS");
					else if(posible.equals(";"))
						componente = new Componente("SIMBOLO ESPECIAL", posible, "PUNTO Y COMA");
					else if(posible.equals(","))
						componente = new Componente("SIMBOLO ESPECIAL", posible, "COMA");
					else 
						componente = new Componente("SIMBOLO ESPECIAL", posible, "PUNTO");
					TablaSimbolos.add(componente);
					indice++;
					return true;
			}
		}
	}
	
	/*---------------- FUNCION IGNORAR -------------------------------------
	 * ENTRADA:
	 * SALIDA:
	 * FUNCIONAMIENTO:
	 */
	public boolean Ignorar (char[] array)
	{
		char caracter = array[indice];
		if(caracter==' ' | caracter=='\n' | caracter=='\t')
		{
			indice++;
			return true;
		}
		else
			return false;
	}

}
